﻿using Sidvall.Data;
using Sidvall.WorkItemManager.Data;
using Sidvall.WorkItemManager.Data.Fields;
using Sidvall.WorkItemManager.Net.Services.V1;
using System.Linq;

namespace Sidvall.WorkItemManager
{
    public static class ParameterManager
    {
        public const string SensorsParameterName = "Sensors";
        public const string DeleteSensorLogParameterName = "DeleteSensorLog";
        public const string ServerIdParameterName = "ServerId";
        public const string ServerConnectionParameterName = "ServerConnection";
        public const string WorkerResetParameterName = "WorkerReset";
        public const string WorkItemResetParameterName = "WorkItemReset";
        public const string WorkItemCleanLogParameterName = "WorkItemCleanLog";
        public const string WorkItemLogParameterName = "WorkItemLog";
        public const string WorkItemUpdateParameterName = "WorkItemUpdate";
        public const string SaveExecutionContextParameterName = "SaveExecutionContext";
        public const string WorkItemSensorGetParameterName = "WorkItemSensorGet";
        public const string WorkItemSensorUpdateParameterName = "WorkItemSensorUpdate";

        #region GetServerConnection

        public static ServerConnection GetServerConnection(ParameterCollection parameters)
        {
            if (parameters == null)
                return null;

            // Find ServerConnection
            var serverConnection = parameters.ValueToString(ParameterManager.ServerConnectionParameterName, null);
            var item = ServerConnection.Deserialize(serverConnection);
            if (item != null)
                return item;

            // Find ServerId
            if (Sidvall.WorkItemManager.SystemContext.Current.UserConfiguration?.ServerConnections == null)
                return null;
            if (Sidvall.WorkItemManager.SystemContext.Current.UserConfiguration.ServerConnections.Items.Count == 1)
            {
                return Sidvall.WorkItemManager.SystemContext.Current.UserConfiguration.ServerConnections.Items[0];
            }
            else
            {
                var serverConnectionId = parameters.ValueToNullableInt32(ParameterManager.ServerIdParameterName);
                return GetServerConnection(serverConnectionId);
            }
        }
        public static ServerConnection GetServerConnection(int? serverConnectionId)
        {
            if (serverConnectionId == null)
                return null;
            if (Sidvall.WorkItemManager.SystemContext.Current.UserConfiguration?.ServerConnections?.Items == null)
                return null;
            return (from o in Sidvall.WorkItemManager.SystemContext.Current.UserConfiguration.ServerConnections.Items
                    where o.ServerConnectionId == serverConnectionId.Value
                    select o).FirstOrDefault();
        }

        #endregion

        #region GetWorkConditionFetchListCriteria

        public static FetchListCriteria<global::Sidvall.WorkItemManager.Data.Fields.WorkConditionField, global::Sidvall.WorkItemManager.Data.Relations.WorkConditionRelation> GetWorkConditionFetchListCriteria(int serverConnectionId)
        {
            FetchListCriteria<global::Sidvall.WorkItemManager.Data.Fields.WorkConditionField, global::Sidvall.WorkItemManager.Data.Relations.WorkConditionRelation> item;

            item = new FetchListCriteria<WorkConditionField, Data.Relations.WorkConditionRelation>();
            InitializeParameters(item, serverConnectionId);

            return item;
        }

        #endregion
        #region GetWorkRetryPolicyListCriteria

        public static FetchListCriteria<global::Sidvall.WorkItemManager.Data.Fields.WorkRetryPolicyField, global::Sidvall.WorkItemManager.Data.Relations.WorkRetryPolicyRelation> GetWorkRetryPolicyListCriteria(int serverConnectionId)
        {
            FetchListCriteria<global::Sidvall.WorkItemManager.Data.Fields.WorkRetryPolicyField, global::Sidvall.WorkItemManager.Data.Relations.WorkRetryPolicyRelation> item;

            item = new FetchListCriteria<WorkRetryPolicyField, Data.Relations.WorkRetryPolicyRelation>();
            InitializeParameters(item, serverConnectionId);

            return item;
        }

        #endregion
        #region GetWorkItemTypeFetchListCriteria

        public static FetchListCriteria<global::Sidvall.WorkItemManager.Data.Fields.WorkItemTypeField, global::Sidvall.WorkItemManager.Data.Relations.WorkItemTypeRelation> GetWorkItemTypeFetchListCriteria(int serverConnectionId)
        {
            FetchListCriteria<global::Sidvall.WorkItemManager.Data.Fields.WorkItemTypeField, global::Sidvall.WorkItemManager.Data.Relations.WorkItemTypeRelation> item;

            item = new FetchListCriteria<WorkItemTypeField, Data.Relations.WorkItemTypeRelation>();
            InitializeParameters(item, serverConnectionId);

            return item;
        }

        #endregion

        #region GetWorkerFetchCriteria

        public static FetchCriteria<global::Sidvall.WorkItemManager.Data.Fields.WorkerField, global::Sidvall.WorkItemManager.Data.Relations.WorkerRelation> GetWorkerFetchCriteria(int serverConnectionId)
        {
            FetchCriteria<global::Sidvall.WorkItemManager.Data.Fields.WorkerField, global::Sidvall.WorkItemManager.Data.Relations.WorkerRelation> item;

            item = new FetchCriteria<WorkerField, Data.Relations.WorkerRelation>();
            InitializeParameters(item, serverConnectionId);

            return item;
        }

        #endregion
        #region GetWorkerFetchListCriteria

        public static FetchListCriteria<global::Sidvall.WorkItemManager.Data.Fields.WorkerField, global::Sidvall.WorkItemManager.Data.Relations.WorkerRelation> GetWorkerFetchListCriteria(int serverConnectionId)
        {
            FetchListCriteria<global::Sidvall.WorkItemManager.Data.Fields.WorkerField, global::Sidvall.WorkItemManager.Data.Relations.WorkerRelation> item;

            item = new FetchListCriteria<WorkerField, Data.Relations.WorkerRelation>();
            InitializeParameters(item, serverConnectionId);

            return item;
        }

        #endregion
        #region GetWorkerResetCommand

        public static CommandCriteria GetWorkerResetCommand(int serverConnectionId, System.Collections.Generic.IEnumerable<long> workerIds, bool? isEnabled)
        {
            CommandCriteria item;

            item = new CommandCriteria()
            {
                CriteriaId = WorkerResetParameterName,
                Parameters = new ParameterCollection(),
            };
            item.Parameters.Add("WorkerIds", workerIds);
            if (isEnabled != null)
                item.Parameters.Add("IsEnabled", isEnabled.Value);
            ParameterManager.InitializeParameters(item.Parameters, serverConnectionId);

            return item;
        }

        #endregion

        #region GetWorkItemCleanLogCommand

        public static CommandCriteria GetWorkItemCleanLogCommand(int? serverConnectionId, System.Collections.Generic.IEnumerable<long> workItemIds,
            int? logDayCount, int? sensorLogDayCount)
        {
            CommandCriteria item;

            item = new CommandCriteria()
            {
                CriteriaId = WorkItemCleanLogParameterName,
                Parameters = new ParameterCollection(),
            };
            item.Parameters.Add("WorkItemIds", workItemIds);
            if (logDayCount != null)
                item.Parameters.Add("LogDayCount", logDayCount.Value);
            if (sensorLogDayCount != null)
                item.Parameters.Add("SensorLogDayCount", sensorLogDayCount.Value);
            ParameterManager.InitializeParameters(item.Parameters, serverConnectionId);

            return item;
        }

        #endregion
        #region GetWorkItemLogCommand

        public static CommandCriteria GetWorkItemLogCommand(Sidvall.WorkItemManager.Data.IWorkItem workItem)
        {
            if (workItem == null)
                return null;
            if (workItem.WorkItemId == null)
                return null;
            if (workItem.LastExecutionEndTime == null)
                return null;
            if (workItem.LastExecutionStartTime == null)
                return null;
            if (workItem.LastWorkItemResultId == null)
                return null;
            return GetWorkItemLogCommand(workItem.ServerConnectionId, workItem.WorkItemId.Value, workItem.LastExecutionEndTime.Value,
                workItem.LastExecutionStartTime.Value, workItem.LastResultMessage, workItem.LastWorkItemResultId.Value);
        }
        public static CommandCriteria GetWorkItemLogCommand(int? serverConnectionId, long workItemId, System.DateTime executionEndTime,
            System.DateTime executionStartTime, string resultMessage, Sidvall.WorkItemManager.Workflow.WorkItemResultType workItemResultId)
        {
            CommandCriteria item;

            item = new CommandCriteria()
            {
                CriteriaId = WorkItemLogParameterName,
                Parameters = new ParameterCollection(),
            };
            item.Parameters.Add(WorkItemField.WorkItemId.ToString(), workItemId);
            item.Parameters.Add(WorkItemLogField.ExecutionEndTime.ToString(), executionEndTime);
            item.Parameters.Add(WorkItemLogField.ExecutionStartTime.ToString(), executionStartTime);
            item.Parameters.Add(WorkItemLogField.ResultMessage.ToString(), resultMessage);
            item.Parameters.Add(WorkItemLogField.WorkItemResultId.ToString(), workItemResultId);
            ParameterManager.InitializeParameters(item.Parameters, serverConnectionId);

            return item;
        }

        #endregion
        #region GetWorkItemResetCommand

        public static CommandCriteria GetWorkItemResetCommand(int? serverConnectionId, System.Collections.Generic.IEnumerable<long> workItemIds,
            Sidvall.WorkItemManager.Workflow.WorkItemStatus? workItemStatusId, bool resetExecution, bool resetExecutionContext, bool resetRetry,
            int? failedExecutionCount, bool resetExecutionHistory, bool? forceExecution, bool? isCanceled, bool? isEnabled)
        {
            CommandCriteria item;

            item = new CommandCriteria()
            {
                CriteriaId = WorkItemResetParameterName,
                Parameters = new ParameterCollection(),
            };
            item.Parameters.Add("WorkItemIds", workItemIds);
            if (workItemStatusId != null)
                item.Parameters.Add("WorkItemStatusId", workItemStatusId.Value);
            item.Parameters.Add("ResetExecution", resetExecution);
            item.Parameters.Add("ResetExecutionContext", resetExecutionContext);
            item.Parameters.Add("ResetRetry", resetRetry);
            if (failedExecutionCount != null)
                item.Parameters.Add("FailedExecutionCount", failedExecutionCount.Value);
            item.Parameters.Add("ResetExecutionHistory", resetExecutionHistory);
            if (forceExecution != null)
                item.Parameters.Add("ForceExecution", forceExecution.Value);
            if (isCanceled != null)
                item.Parameters.Add("IsCanceled", isCanceled.Value);
            if (isEnabled != null)
                item.Parameters.Add("IsEnabled", isEnabled.Value);
            ParameterManager.InitializeParameters(item.Parameters, serverConnectionId);

            return item;
        }

        #endregion
        #region GetWorkItemUpdateCommand

        public static CommandCriteria GetWorkItemUpdateCommand(Sidvall.WorkItemManager.Data.IWorkItem workItem, bool saveExecutionContext)
        {
            if (workItem == null)
                return null;
            if (workItem.WorkItemId == null)
                return null;
            return GetWorkItemUpdateCommand(workItem.ServerConnectionId, workItem.WorkItemId.Value, workItem.WorkItemStatusId,
                workItem.ExecutionStartTime, workItem.ExecutionContext, workItem.ExecutionContextUpdated, workItem.ExecutionCompletionPercentage,
                workItem.RetryCount, workItem.RetryTime, workItem.FailedExecutionCount, workItem.LastExecutionStartTime,
                workItem.LastExecutionEndTime, workItem.LastWorkItemResultId, workItem.LastResultMessage, saveExecutionContext);
        }
        public static CommandCriteria GetWorkItemUpdateCommand(int? serverConnectionId, long workItemId, Sidvall.WorkItemManager.Workflow.WorkItemStatus? workItemStatus,
            System.DateTime? executionStartTime, string executionContext, System.DateTime? executionContextUpdated, byte? executionCompletionPercentage,
            int? retryCount, System.DateTime? retryTime, int? failedExecutionCount, System.DateTime? lastExecutionStartTime,
            System.DateTime? lastExecutionEndTime, Sidvall.WorkItemManager.Workflow.WorkItemResultType? lastWorkItemResultId, string lastResultMessage,
            bool saveExecutionContext)
        {
            CommandCriteria item;

            item = new CommandCriteria()
            {
                CriteriaId = WorkItemUpdateParameterName,
                Parameters = new ParameterCollection(),
            };
            item.Parameters.Add(WorkItemField.WorkItemId.ToString(), workItemId);
            if (workItemStatus != null)
                item.Parameters.Add(WorkItemField.WorkItemStatusId.ToString(), workItemStatus.Value);
            if (executionStartTime != null)
                item.Parameters.Add(WorkItemField.ExecutionStartTime.ToString(), executionStartTime.Value);
            item.Parameters.Add(WorkItemField.ExecutionContext.ToString(), executionContext);
            if (executionContextUpdated != null)
                item.Parameters.Add(WorkItemField.ExecutionContextUpdated.ToString(), executionContextUpdated.Value);
            if (executionCompletionPercentage != null)
                item.Parameters.Add(WorkItemField.ExecutionCompletionPercentage.ToString(), executionCompletionPercentage.Value);
            if (retryCount != null)
                item.Parameters.Add(WorkItemField.RetryCount.ToString(), retryCount.Value);
            if (retryTime != null)
                item.Parameters.Add(WorkItemField.RetryTime.ToString(), retryTime.Value);
            if (failedExecutionCount != null)
                item.Parameters.Add(WorkItemField.FailedExecutionCount.ToString(), failedExecutionCount.Value);
            if (lastExecutionStartTime != null)
                item.Parameters.Add(WorkItemField.LastExecutionStartTime.ToString(), lastExecutionStartTime.Value);
            if (lastExecutionEndTime != null)
                item.Parameters.Add(WorkItemField.LastExecutionEndTime.ToString(), lastExecutionEndTime.Value);
            if (lastWorkItemResultId != null)
                item.Parameters.Add(WorkItemField.LastWorkItemResultId.ToString(), lastWorkItemResultId.Value);
            item.Parameters.Add(WorkItemField.LastResultMessage.ToString(), lastResultMessage);
            item.Parameters.Add(SaveExecutionContextParameterName, saveExecutionContext);
            ParameterManager.InitializeParameters(item.Parameters, serverConnectionId);

            return item;
        }

        #endregion
        #region GetWorkItemFetchCriteria

        public static FetchCriteria<global::Sidvall.WorkItemManager.Data.Fields.WorkItemField, global::Sidvall.WorkItemManager.Data.Relations.WorkItemRelation> GetWorkItemFetchCriteria(int serverConnectionId)
        {
            FetchCriteria<global::Sidvall.WorkItemManager.Data.Fields.WorkItemField, global::Sidvall.WorkItemManager.Data.Relations.WorkItemRelation> item;

            item = new FetchCriteria<WorkItemField, Data.Relations.WorkItemRelation>();
            InitializeParameters(item, serverConnectionId);

            return item;
        }

        #endregion
        #region GetWorkItemFetchListCriteria

        public static FetchListCriteria<global::Sidvall.WorkItemManager.Data.Fields.WorkItemField, global::Sidvall.WorkItemManager.Data.Relations.WorkItemRelation> GetWorkItemFetchListCriteria(int serverConnectionId)
        {
            FetchListCriteria<global::Sidvall.WorkItemManager.Data.Fields.WorkItemField, global::Sidvall.WorkItemManager.Data.Relations.WorkItemRelation> item;

            item = new FetchListCriteria<WorkItemField, Data.Relations.WorkItemRelation>();
            InitializeParameters(item, serverConnectionId);

            return item;
        }

        #endregion
        #region GetWorkItemLogFetchListCriteria

        public static FetchListCriteria<global::Sidvall.WorkItemManager.Data.Fields.WorkItemLogField, global::Sidvall.WorkItemManager.Data.Relations.WorkItemLogRelation> GetWorkItemLogFetchListCriteria(int serverConnectionId)
        {
            var item = new FetchListCriteria<WorkItemLogField, Data.Relations.WorkItemLogRelation>();
            InitializeParameters(item, serverConnectionId);
            return item;
        }

        #endregion

        #region GetWorkItemSensorsUpdateCommand

        public static CommandCriteria GetWorkItemSensorsUpdateCommand(int? serverConnectionId, long workItemId, bool logOldValue, SensorValueCollection sensors)
        {
            CommandCriteria item;

            if ((sensors == null) || (sensors.Count == 0))
                return null;

            item = new CommandCriteria()
            {
                CriteriaId = WorkItemSensorUpdateParameterName,
                Parameters = new ParameterCollection(),
            };
            if (serverConnectionId != null)
                item.Parameters.Add(WorkItemField.ServerConnectionId.ToString(), serverConnectionId.Value);
            item.Parameters.Add(WorkItemField.WorkItemId.ToString(), workItemId);
            item.Parameters.Add("LogOldValue", logOldValue);
            item.Parameters.Add(ParameterManager.SensorsParameterName, sensors);

            return item;
        }

        #endregion

        #region InitializeParameters

        public static void InitializeParameters(ISaveContext context, int? serverConnectionId)
        {
            if (context == null)
                return;
            if (context.Settings == null)
            {
                if (serverConnectionId != null)
                    context.Settings = new SaveSettings();
            }
            InitializeParameters(context.Settings, serverConnectionId);
        }
        public static void InitializeParameters(CriteriaBase criteria, int? serverConnectionId)
        {
            if (criteria == null)
                return;
            if (criteria.Parameters == null)
            {
                if (serverConnectionId != null)
                    criteria.Parameters = new ParameterCollection();
            }
            InitializeParameters(criteria.Parameters, serverConnectionId);
        }
        public static void InitializeParameters(ParameterCollection parameters, int? serverConnectionId)
        {
            if (parameters == null)
                return;
            parameters.Remove(ServerIdParameterName);
            if (serverConnectionId != null)
                parameters.Add(ServerIdParameterName, serverConnectionId.Value);
        }

        public static void InitializeParameters(ISaveContext context, ServerConnection serverConnection)
        {
            if (context == null)
                return;
            if (context.Settings == null)
            {
                if (serverConnection != null)
                    context.Settings = new SaveSettings();
            }
            InitializeParameters(context.Settings, serverConnection);
        }
        public static void InitializeParameters(CriteriaBase criteria, ServerConnection serverConnection)
        {
            if (criteria == null)
                return;
            if (criteria.Parameters == null)
            {
                if (serverConnection != null)
                    criteria.Parameters = new ParameterCollection();
            }
            InitializeParameters(criteria.Parameters, serverConnection);
        }
        public static void InitializeParameters(ParameterCollection parameters, ServerConnection serverConnection)
        {
            if (parameters == null)
                return;
            parameters.Remove(ServerConnectionParameterName);
            if (serverConnection != null)
                parameters.Add(ServerConnectionParameterName, serverConnection.Serialize());
        }

        #endregion
    }
}
